"""
前提:内存视图
    >>> numbers = array.array('h', [-2, -1, 0, 1, 2]) 
    >>> memv = memoryview(numbers)
    >>> tuple(memv)
    (-2, -1, 0, 1, 2)
    >>> len(memv)
    5
    >>> memv[0]
    -2
    >>> memv_oct = memv.cast('B') # 无符号字符 即16bit
    >>> tuple(memv_oct)
    (254, 255, 255, 255, 0, 0, 1, 0, 2, 0)
    >>> memv_oct[5] = 4
    >>> numbers
    array('h', [-2, -1, 1024, 1, 2])

模拟向量
    >>> # 正式测试
    >>> v1 = V2d(3,4)
    >>> print(v1.x, v1.y)
    3.0 4.0
    >>> x,y = v1
    >>> x,y
    (3.0, 4.0)
    >>> print(v1)
    (3.0, 4.0)
    >>> v1
    V2d(3.0, 4.0)
    >>> abs(v1)
    5.0
    >>> bool(v1), bool(V2d(0,0))
    (True, False)
    >>> v1 == [3.0, 4.0]
    True
    >>> format(v1, '.3fp') # doctest: +ELLIPSIS
    '<5.000, 0.927>'

构造方法eval vs from bytes
    >>> v1c = eval(repr(v1))
    >>> v1c
    V2d(3.0, 4.0)
    >>> v1 == v1c
    True
    >>> v1_clone = V2d.from_bytes(bytes(v1))

字节操作
    >>> octets = bytes(v1) # 字节码
    >>> octets
    b'd\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'
    >>> v1.raw_bytes = True;octets = bytes(v1)
    >>> octets
    b'\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@'

"""

import math
import array


class V2d:
    typecode = "d"
    raw_bytes = False

    def __init__(self, x, y):
        self.x = float(x)
        self.y = float(y)

    def __iter__(self):
        # return (i for i in (self.x, self.y))
        yield self.x
        yield self.y

    def __str__(self):
        return f"({self.x}, {self.y})"

    def __repr__(self):
        # return f"{type(self).__name__}({self.x}, {self.y})"
        return "{}({!r}, {!r})".format(type(self).__name__, *self)

    def __abs__(self):
        return math.hypot(self.x, self.y)

    def __bool__(self):
        return not (self.x == 0 and self.y == 0)

    def __eq__(self, other):
        # return self.x == other.x and self.y == other.y
        return tuple(self) == tuple(other)

    def __bytes__(self):
        # print("raw with out typecode", self.raw_bytes)
        return (bytes() if self.raw_bytes else bytes([ord(self.typecode)])) + bytes(
            array.array(self.typecode, self)
        )

    def angle(self):
        return math.atan2(self.y, self.x)

    def __format__(self, fmt_spec=""):
        def inner_fmt(it, fmt):
            return (format(x, fmt) for x in it)

        if fmt_spec.endswith("p"):
            fmt_spec = fmt_spec[:-1]
            ret = (abs(self), self.angle())
            return "<{}, {}>".format(*inner_fmt(ret, fmt_spec))
        else:
            print(inner_fmt(self, fmt_spec))
            return "({}, {})".format(*inner_fmt(self, fmt_spec))

    @classmethod
    def from_bytes(cls, octets):
        memv = memoryview(octets[1 if not cls.raw_bytes else 0 :]).cast(cls.typecode)
        return cls(*memv)


if __name__ == "__main__":
    import doctest

    print("v2d 测试开始")
    (ff, tt) = doctest.testmod()
    print("测试结束:统计-失败{},总计{}".format(ff, tt))
    print("√" * tt if tt > 0 and not ff else "无测试" if not ff else "×" * ff)
